require 'rubygems'
require 'sqlite3'

require 'config.rb'

require 'TalkCommand'
require 'TalkLeaning'
require 'TalkSupport'
require 'TalkOmake'

class TalkClass

	def initialize
		srand(Time.now.to_i)
		if(FileTest.exists?('talk.db')) then
			@talkdb = SQLite3::Database.new("talk.db")
		else
			@talkdb = SQLite3::Database.new("talk.db")
			sql ='create table reply ('
			sql+='get text not null primary key'
			sql+=',say text not null'
			sql+=',flag text not null' #SAY_TO_ME or SAY_TO_US
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into reply values (:get,:say,:flag);'
			@talkdb.execute(sql,:get=>'こんにちは',:say=>'こんにちは！|こんちわ！',:flag=>'SAY_TO_US')
			@talkdb.execute(sql,:get=>'好きな食べ物は',:say=>'%my-likeFood%です。',:flag=>'SAY_TO_ME')

			sql ='create table trans ('
			sql+='key text not null primary key'
			sql+=',value text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into trans values (:key,:value);'
			@talkdb.execute(sql,:key=>'好きな食べ物は',:value=>'好きな食べ物は')
			@talkdb.execute(sql,:key=>'こんにちは',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'こんちわ',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'Hello',:value=>'こんにちは')
			@talkdb.execute(sql,:key=>'Hi',:value=>'こんにちは')

			sql ='create table personal ('
			sql+='id integer primary key'
			sql+=',name text not null'
			sql+=',key text not null'
			sql+=',value text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into personal values (:id,:name,:key,:value);'
			@talkdb.execute(sql,:name=>'my',:key=>'name',:value=>$config[:MY_NAME])
			@talkdb.execute(sql,:name=>'my',:key=>'likeFood',:value=>'沖縄そば')
			@talkdb.execute(sql,:name=>'testUser',:key=>'name',:value=>'テストなユーザ')

			sql ='create table speak ('
			sql+='id integer primary key'
			sql+=',time text not null' #every/morning/afterNoon/teaTime/evening/night or 24time
			sql+=',message text not null'
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into speak values (:id,:time,:message);'
			@talkdb.execute(sql,:time=>'every',:message=>'<NowTime>をお知らせします。')
			@talkdb.execute(sql,:time=>'2000',:message=>'8時、そろそろおなか空いたかも。')
			@talkdb.execute(sql,:time=>'night',:message=>'夜ですね、わかります。')

			sql ='create table dict ('
			sql+='key text primary key'
			sql+=',value text not null'
			sql+=',type text not null' #updown/mean
			sql+=');'
			@talkdb.execute(sql)
			sql ='insert into dict values (:key,:value,:type);'
			@talkdb.execute(sql,:key=>'車',:value=>'リバティ',:type=>'updown')
			@talkdb.execute(sql,:key=>'IT',:value=>'Infomation Technology：情報技術',:type=>'mean')

			loading_files('trans',$config[:TRANS_DATA_FILE])
			loading_files('reply',$config[:REPLY_DATA_FILE])
			loading_files('personal',$config[:PERSONAL_DATA_FILE])
			loading_files('speak',$config[:SPEAK_DATA_FILE])
			loading_files('dict',$config[:DICT_DATA_FILE])
		end
	end

	#メッセージを分類する。
	def parse(type='',from_name='',tweet='')
		#puts "[DEBUG:parse] #{type} #{from_name} #{tweet}"
		reply_message=''
		return '' if(from_name==$config[:MY_NAME])

		#とりあえず、短縮URLを元に戻す。
		tweet = replace_uri(tweet,'expand')

		case type
		when 'DM'
			reply_message=think_message(from_name)
		when 'TW'
			if (/@#{$config[:MY_NAME]}/ =~ tweet) then #自分宛のツィート
				puts "#{from_name}から話しかけられました"
				reply_message = think_answer(from_name,tweet,'reply') #返事をする
			else #それ以外
				puts "#{from_name}がなにか言ってます"
				reply_message = think_answer(from_name,tweet,'say') #話しかける
			end
		#else #自分から話しかける
		#	reply_message = think_tweet
		end
		if(reply_message['message']!=nil)then
			#メッセージ中のURLを短縮
			reply_message['message'] = replace_uri(reply_message['message'])
			#文字数制限にかからないように文章を短縮
			reply_message['message'] = shorten_message(reply_message['message'])
		end
		return reply_message
	end

	#DMへの返事
	def think_message(from_name='')
		message="お手紙ありがとう！後で返事書くからね"
		return {'to'=>from_name,'message'=>message,'order'=>''}
	end
	
	#誰かから話しかけられたときの返事
	def think_answer(from_name='',tweet='',mode='')
		return '' if (from_name=='' or tweet=='')
		return '' if (from_name==$config[:MY_NAME])
		message=''
		answer=''

		#自分宛のアレを消す
		tweet.gsub!("@#{$config[:MY_NAME]} ","")

		#特定のツィートには特別な返事をするよ
		result = special(tweet,mode,from_name)
		result['message'] = "#{result['message']} RT #{tweet}" if(result!=nil)
		return {'to'=>from_name,'message'=>result['message'],'order'=>result['order']} if(result!=nil)

		#(1) 区切り文字で文節に分割
		phrase = tweet.split(/[,.!?、。！？\s\n]/)
		phrase.delete("")
		#phrase.delete("@#{$config[:MY_NAME]}")
		
		#(2)文節ごとに返答を考える
		phrase.each{|str|
			choices = search_choices(str,true) if (mode=='reply') #返事をする
			choices = search_choices(str,false) if (mode=='say') #話しかける
			message+=choices[rand(choices.size)] if(choices!=nil)
		}
		answer_tmp = replace(message,from_name) #テンプレ対応
		answer = command(answer_tmp) #コマンド対応
		return {'to'=>from_name,'message'=>answer,'order'=>''} if(answer!='')
		return ''
	end

	#独り言をしゃべる
	def think_tweet(nowH=0,nowM=0)
		order=''
		#(1)現在時刻を調べます、ただし10分くぎりです。
		nowH = Time.now.strftime("%H").to_i if(nowH==0)
		nowM = Time.now.strftime("%M").to_i if(nowM==0)
		nowM = (nowM/10)*10 #10分区切りではかります。
		time = nowH*100+nowM
		time_name = ''

		#(2)時間帯を判定
		case time
		when 600 .. 1200
			time_name = 'morning'
		when 1430 .. 1530
			time_name = 'teaTime'
		when 1200 .. 1700
			time_name = 'afterNoon'
		when 1700 .. 2000
			time_name = 'evening'
		else
			time_name = 'night'
		end

		#(3)テーブルから引いてくる
		result=nil
		sql = "select message from speak where time=='every' or time=='#{time_name}' or time=='#{time}';"
		begin
			result = @talkdb.execute(sql);
		rescue SQLite3::SQLException
			error_time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{error_time}\t[ERROR:think_tweet] database access error"
		end
		result.flatten! if(result!=nil)

		#選択肢の中から適当に１つ選ぶ
		message =  result[rand(result.size)]
		message_tmp = replace(message)#テンプレ対応
		return {'message'=>command(message_tmp),'order'=>order}#コマンド対応
	end

	#1)単語が言い換えテーブルにあるか調べる
	#2)あったら返事テーブルを調べる
	#3)返事の種類を配列で返す
	def search_choices(str,personal_mode=true)
		#puts "search_choices #{str}"
		result=nil
		begin
			new_key = @talkdb.execute("select value from trans where key=='#{str}';")
			new_key.flatten! if(new_key!=nil)
			if (personal_mode) then
				choices = @talkdb.execute("select say from reply where get=='#{new_key[0]}';")
			else
				choices = @talkdb.execute("select say from reply where get=='#{new_key[0]}' and flag=='SAY_TO_US';")
			end
			if (choices!=nil) then
				choices.flatten!
				result = choices[0].split("|") if (choices[0]!=nil)
			end
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:search_choices] database access error"
		end
		return result
	end

	#あらかじめ設定されている文字列を置き換え
	def replace(str,from_name='')
		source = str.scan(/%[a-zA-Z0-9]*_[a-zA-Z0-9]*%/)
		source.each{|command|
			keys = command.gsub("%",'').split('_')
			if (keys[0] == 'user') then
				keys[0] = from_name
			end
			result = @talkdb.execute("select value from personal where name=='#{keys[0]}' and key=='#{keys[1]}';")
			result.flatten! if(result!=nil)
			str.sub!(command,result[0]) if(result[0]!=nil)
			str.sub!(command,from_name) if(result[0]==nil and keys[1]=='name')
		}
		return str
	end

	def pub_command(str='')
		return command(str) if(str!='')
	end

	#特別な対応を考えます
	def special(message='',mode='',from_name='')
		answer=''

		answer = for_special_friend(message,from_name)
		return answer if(answer!='')

		#Twitter Order
		case message
		when %r((follow|フォロー)して),%r((友達|友人)になって)
			return {'message'=>"OK、これからよろしく！",'order'=>'follow'} if(mode=='reply')
		when %r((remove|リムーブ|unfollow|アンフォロー)して)
			return {'message'=>'そう？ちょっとまってね。。。','order'=>'unfollow'} if(mode=='reply')
		when %r((^\[RT\]|^\[拡散希望\]))
			return {'message'=>'OK！協力するよ！','order'=>'retweet'}
		end
		
		#外部サービス
		case message
		when %r(http://shindanmaker.com/(\d+))
			id = $1.to_i
			resp = get_shindan_maker(id,$config[:MY_NAME])
			return {'message'=>resp,'order'=>''} if(resp!='')
		when %r((^\[DO\]|^\[関連\]))
			resp = url_relevance_search(message,'cinii')
			return {'message'=>resp,'order'=>''} if(resp!='')
		end

		#以降、RTより後ろは削除
		rtindex = message.index("RT")
		message = message[0..rtindex] if(rtindex!=nil)

		#学習成果を教えてあげる
		case message
		when %r(「(.*)」て(何|どういう意味))
			str=$1
			result = search_dict(str)
			result.flatten!
			answer = "#{str}は「#{result[0]}」てゆう意味だよ！" if(result.size>0)
			if (answer!='') then
				return {'message'=>answer,'order'=>''}
			else
				return {'message'=>"う〜ん、なんだろう？",'order'=>''}
			end
		when %r(「(.*)」の仲間)
			str=$1
			result = search_dict(str,'updown')
			result.flatten!
			answer = "#{str}の仲間は#{result[rand(result.size)]}とかだよ〜"
			if (answer!='') then
				return {'message'=>answer,'order'=>''}
			else
				return {'message'=>"ごめんね、わからないの、、、おしえて？\n[「xxx」は「ooo」の仲間]って言ってくれると覚えるよ",'order'=>''}
			end
		end

		#学習
		learn_data = learn(message)
		return nil if(learn_data==nil)
		learn_data.each{|data|
			case data['table']
			when 'speak'
				res = append_speak(data['time'],data['message'])
				answer = "ありがとう！" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			when 'reply'
				res = append_reply(data['key'],data['value'])
				answer = "わかった！" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			when 'trans'
				res = append_trans(data['key'],data['value'])
				answer = "覚えたよ！" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			when 'dict'
				res = append_dict(data['key'],data['value'],data['type'])
				answer = "そーなのかー" if(res!=nil)
				return {'message'=>answer,'order'=>''} if(answer!='')
			end
		}
		return nil
	end

##データベース　はじめ
	#CSVファイルを読み込んでそれぞれのデータベースに登録する
	def loading_files(mode,file_name)
		if (file_name!=nil and FileTest.exists?(file_name)) then
			file = open(file_name)
		else
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:loading_files] #{file_name} is not exist"
		end
		file.each {|line|
			datas = line.split(',')
			case mode
			when 'reply'
				append_reply(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			when 'trans'
				append_trans(datas[0],datas[1]) if(datas[0]!=nil and datas[1]!=nil)
			when 'personal'
				append_personal(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			when 'speak'
				append_speak(datas[0],datas[1]) if(datas[0]!=nil and datas[1]!=nil)
			when 'dict'
				append_dict(datas[0],datas[1],datas[2]) if(datas[0]!=nil and datas[1]!=nil and datas[2]!=nil)
			end
		}
		file.close
	end

	#replyテーブルへの追加
	def append_reply(get='',say='',flag='')
		return nil if (get==''or say=='')
		begin
			nowdata = @talkdb.execute("select get,say from reply where get='#{get}'")
			
			if(nowdata.size==0) then
				sql ='insert into reply values (:get,:say,:flag);'
				#まだ登録されてないなら
				if(flag!='') then
					result = @talkdb.execute(sql,:get=>get,:say=>say,:flag=>flag.chomp) 
				else
					result = @talkdb.execute(sql,:get=>get,:say=>say,:flag=>'SAY_TO_US')
				end
				result = append_trans(get,get)
			else
				if (nowdata[0][1] != say) then
					newdata = "#{nowdata[0][1]}|#{say}"
					sql ="update reply set say='#{newdata}' where get='#{get}';"
					result = @talkdb.execute(sql)
				end
			end
			return result
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_reply] database access error"
		end
		return nil
	end
	#personalテ−ブルへの追加
	def append_personal(name='',key='',value='')
		return nil if(name=='' or key=='' or value=='')
		
		sql ='insert into personal values (:id,:name,:key,:value);'
		begin
			return @talkdb.execute(sql,:name=>name,:key=>key,:value=>value.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_personal] database access error"
		end
		return nil
	end
	#transテ−ブルへの追加
	def append_trans(key='',value='')
		return nil if(key=='' or value=='')
		sql ='insert into trans values (:key,:value);'
		begin
			return @talkdb.execute(sql,:key=>key,:value=>value.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_trans] database access error"
		end
		return nil
	end
	#speakテ−ブルへの追加
	def append_speak(time='',message='')
		return nil if(time=='' or message=='')
		sql ='insert into speak values (:id,:time,:message);'
		begin
			return @talkdb.execute(sql,:time=>time,:message=>message.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_speak] database access error"
		end
		return nil
	end
	#dictテ−ブルへの追加
	def append_dict(key='',value='',type='')
		return nil if(type=='' or key=='' or value=='')
		sql ='insert into dict values (:key,:value,:type);'
		begin
			return @talkdb.execute(sql,:key=>key,:value=>value,:type=>type.chomp)
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:append_dict] database access error"
		end
		return nil
	end
	#dictテーブルを検索
	def search_dict(key='',type='mean')
		return nil if(key=='')
		begin
			return @talkdb.execute("select value from dict where key='#{key}' and type='#{type}'")
		rescue SQLite3::SQLException
			time = Time.now.strftime("%Y/%m/%d %H:%M:%S")
			puts "#{time}\t[ERROR:search_dict] database access error"
		end
		return nil
	end
##データベース　おわり

end
